import { EventEmitter } from 'events'
import { levelConfig } from '../../config/level'
import { User } from '../../models/User'
import { AppError } from '../../utils/AppError'
import { RedisService } from '../redis/RedisService'

export class UserLevelService extends EventEmitter {
  private redis: RedisService

  constructor() {
    super()
    this.redis = new RedisService()
  }

  // 增加经验值
  async addExp(userId: string, exp: number, type: string) {
    const user = await User.findById(userId)
    if (!user) {
      throw new AppError(404, '用户不存在')
    }

    // 获取当前等级信息
    const currentLevel = levelConfig.levels.find((l) => l.level === user.level)
    if (!currentLevel) {
      throw new AppError(500, '等级配置错误')
    }

    // 计算新经验值
    const newExp = user.exp + exp
    let newLevel = user.level
    let rewards = []

    // 检查是否升级
    while (true) {
      const nextLevel = levelConfig.levels.find((l) => l.level === newLevel + 1)
      if (!nextLevel || newExp < nextLevel.exp) break

      newLevel++
      rewards.push(nextLevel.rewards)

      // 触发升级事件
      this.emit('level_up', {
        userId,
        oldLevel: newLevel - 1,
        newLevel,
        rewards: nextLevel.rewards,
      })
    }

    // 更新用户信息
    await User.findByIdAndUpdate(userId, {
      exp: newExp,
      level: newLevel,
    })

    // 记录经验获取历史
    await this.saveExpHistory(userId, {
      type,
      exp,
      time: Date.now(),
    })

    // 发放升级奖励
    if (rewards.length > 0) {
      await this.grantLevelRewards(userId, rewards)
    }

    // 更新等级排行榜
    await this.updateLevelRanking(userId, newLevel, newExp)

    return {
      oldExp: user.exp,
      newExp,
      oldLevel: user.level,
      newLevel,
      rewards,
    }
  }

  // 获取用户等级信息
  async getUserLevel(userId: string) {
    const user = await User.findById(userId).select('level exp badges titles')

    if (!user) {
      throw new AppError(404, '用户不存在')
    }

    const currentLevel = levelConfig.levels.find((l) => l.level === user.level)
    const nextLevel = levelConfig.levels.find((l) => l.level === user.level + 1)

    return {
      level: user.level,
      exp: user.exp,
      badges: user.badges,
      titles: user.titles,
      currentLevel,
      nextLevel,
      progress: nextLevel ? (user.exp - currentLevel.exp) / (nextLevel.exp - currentLevel.exp) : 1,
    }
  }

  // 获取等级排行榜
  async getLevelRanking(type: 'exp' | 'level' = 'level', limit: number = 50) {
    const key = `ranking:${type}`
    const ranking = await this.redis.zrevrange(key, 0, limit - 1, 'WITHSCORES')

    const result = []
    for (let i = 0; i < ranking.length; i += 2) {
      const userId = ranking[i]
      const score = parseInt(ranking[i + 1])
      const user = await User.findById(userId).select('nickname avatar level exp badges titles')

      result.push({
        rank: i / 2 + 1,
        userId,
        nickname: user.nickname,
        avatar: user.avatar,
        level: user.level,
        exp: user.exp,
        badge: user.badges[0],
        title: user.titles[0],
        score,
      })
    }

    return result
  }

  // 发放等级奖励
  private async grantLevelRewards(userId: string, rewards: any[]) {
    const multi = this.redis.multi()

    for (const reward of rewards.flat()) {
      switch (reward.type) {
        case 'coins':
          await User.findByIdAndUpdate(userId, {
            $inc: { coins: reward.amount },
          })
          break
        case 'badge':
          await User.findByIdAndUpdate(userId, {
            $addToSet: { badges: reward.badge },
          })
          break
        case 'title':
          await User.findByIdAndUpdate(userId, {
            $addToSet: { titles: reward.title },
          })
          break
        case 'privilege':
          multi.sadd(`user:${userId}:privileges`, reward.privilege)
          break
      }
    }

    await multi.exec()
  }

  // 保存经验历史
  private async saveExpHistory(userId: string, record: any) {
    const key = `user:${userId}:exp_history`
    await this.redis.lpush(key, JSON.stringify(record))
    await this.redis.ltrim(key, 0, levelConfig.history.maxLength - 1)
  }

  // 更新等级排行榜
  private async updateLevelRanking(userId: string, level: number, exp: number) {
    const multi = this.redis.multi()
    multi.zadd('ranking:level', level, userId)
    multi.zadd('ranking:exp', exp, userId)
    await multi.exec()
  }
}
